#include "../include/LHG_Git.h"

char *USERNAME = NULL;
char *PASSWORD = NULL;

int lhg_error(int error)
{
    if (error < 0)
    {
        const git_error *e = git_error_last();
        printf("Error %d/%d: %s\n", error, e->klass, e->message);
    }
    return 0;
}

int lhg_fetchhead_ref_cb(const char *name, const char *url, const git_oid *oid, unsigned int is_merge, void *payload)
{
    lhg_error(git_oid_cpy((git_oid *)payload, oid));
    return 0;
}

int lhg_credentials_cb(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, void *payload)
{
    return git_cred_userpass_plaintext_new(out, USERNAME, PASSWORD);
}

void lhg_set_userpass(const char *username, const char *password)
{
    USERNAME = (char *)username;
    PASSWORD = (char *)password;
}

void lhg_set_userpass_free()
{
    USERNAME = NULL;
    PASSWORD = NULL;
}

void lhg_init(const char *path, const char *name, const char *email)
{
    git_libgit2_init();
    git_repository *repo;
    git_signature *me;
    git_index *index;
    git_oid tree_id, commit_id;
    git_tree *tree;
    lhg_error(git_repository_init(&repo, path, 0));
    lhg_error(git_signature_now(&me, name, email));
    lhg_error(git_repository_index(&index, repo));
    lhg_error(git_index_write_tree(&tree_id, index));
    lhg_error(git_tree_lookup(&tree, repo, &tree_id));
    lhg_error(git_commit_create_v(
        &commit_id, repo, "HEAD", me, me,
        NULL, "Initial LHG dir", tree, 0));
}

void lhg_commit(const char *path, const char *name, const char *email, const char *message)
{
    git_libgit2_init();
    git_oid commit_oid, tree_oid;
    git_tree *tree;
    git_index *index;
    git_object *parent;
    git_reference *ref;
    git_signature *me;
    git_repository *repo;
    lhg_error(git_signature_now(&me, name, email));
    lhg_error(git_repository_open(&repo, path));
    lhg_error(git_revparse_ext(&parent, &ref, repo, "HEAD"));
    lhg_error(git_repository_index(&index, repo));
    lhg_error(git_index_write_tree(&tree_oid, index));
    lhg_error(git_index_write(index));
    lhg_error(git_tree_lookup(&tree, repo, &tree_oid));
    lhg_error(git_commit_create_v(
        &commit_oid,
        repo,
        "HEAD",
        me,
        me,
        NULL,
        message,
        tree,
        1,
        parent));
    git_libgit2_shutdown();
}

void lhg_clone(const char *url, const char *path, const char *username, const char *password)
{
    git_libgit2_init();
    git_repository *repo;
    git_clone_options clone_options = GIT_CLONE_OPTIONS_INIT;
    git_fetch_options fetch_options = GIT_FETCH_OPTIONS_INIT;
    lhg_set_userpass(username, password);
    fetch_options.callbacks.credentials = lhg_credentials_cb;
    clone_options.fetch_opts = fetch_options;
    lhg_error(git_clone(&repo, url, path, &clone_options));
    lhg_set_userpass_free();
    git_libgit2_shutdown();
}

void lhg_remote(const char *path, const char *url)
{
    git_libgit2_init();
    git_repository *repo;
    git_remote *newremote;
    git_reference *branch;
    lhg_error(git_repository_open(&repo, path));
    lhg_error(git_remote_create(&newremote, repo, "origin", url));
    lhg_error(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
    lhg_error(git_branch_set_upstream(branch, "master"));
    git_libgit2_shutdown();
}

void lhg_push(const char *path, const char *username, const char *password)
{
    git_libgit2_init();
    git_push_options options;
    git_remote *remote;
    git_repository *repo;
    char *refspec = (char *)"refs/heads/master";
    const git_strarray refspecs = {
        &refspec,
        1};
    lhg_error(git_repository_open(&repo, path));
    lhg_error(git_remote_lookup(&remote, repo, "origin"));
    lhg_error(git_push_options_init(&options, GIT_PUSH_OPTIONS_VERSION));
    lhg_set_userpass(username, password);
    options.callbacks.credentials = lhg_credentials_cb;
    lhg_error(git_remote_push(remote, &refspecs, &options));
    lhg_set_userpass_free();
    git_libgit2_shutdown();
}

void lhg_add(const char *path, const char *file)
{
    git_index *index;
    git_oid tree;
    git_repository *repo;
    git_libgit2_init();
    lhg_error(git_repository_open(&repo, path));
    lhg_error(git_repository_index(&index, repo));
    lhg_error(git_index_add_bypath(index, file));
    lhg_error(git_index_write(index));
    lhg_error(git_index_write_tree(&tree, index));
    git_libgit2_shutdown();
}

void lhg_remove(const char *path, const char *file)
{
    git_index *index;
    git_oid tree;
    git_repository *repo;
    git_libgit2_init();
    lhg_error(git_repository_open(&repo, path));
    lhg_error(git_repository_index(&index, repo));
    lhg_error(git_index_remove_bypath(index, file));
    lhg_error(git_index_write(index));
    lhg_error(git_index_write_tree(&tree, index));
    git_libgit2_shutdown();
}

void lhg_pull(const char *path, const char *name, const char *email, const char *username, const char *password)
{
    git_libgit2_init();
    git_repository *repo;
    git_remote *remote;
    git_signature *me;
    git_annotated_commit *branch;
    git_annotated_commit *onto;
    git_reference *ref;
    git_oid id;
    git_rebase *rebase;
    git_rebase_operation *op;
    git_oid rebaseOID = {{0}};
    git_fetch_options fetch_options = GIT_FETCH_OPTIONS_INIT;
    lhg_set_userpass(username, password);
    fetch_options.callbacks.credentials = lhg_credentials_cb;
    git_rebase_options rebase_options = GIT_REBASE_OPTIONS_INIT;
    lhg_error(git_repository_open(&repo, path));
    lhg_error(git_remote_lookup(&remote, repo, "origin"));
    lhg_error(git_remote_fetch(remote, NULL, &fetch_options, NULL));
    lhg_error(git_repository_fetchhead_foreach(repo, lhg_fetchhead_ref_cb, &id));
    lhg_error(git_annotated_commit_lookup(&onto, repo, &id));
    lhg_error(git_branch_lookup(&ref, repo, "master", GIT_BRANCH_LOCAL));
    lhg_error(git_annotated_commit_from_ref(&branch, repo, ref));
    lhg_error(git_rebase_init(&rebase, repo, branch, NULL, onto, &rebase_options));
    lhg_error(git_signature_now(&me, name, email));
    while ((git_rebase_next(&op, rebase)) == 0)
    {
        lhg_error(git_rebase_commit(&rebaseOID, rebase, NULL, me, NULL, NULL));
    }
    lhg_error(git_rebase_finish(rebase, me));
    lhg_set_userpass_free();
    git_libgit2_shutdown();
}
